const T = require("./pub/tools");
const Hook = require("./baseHook");

const emptyPromise = new Promise((res)=>{ 
    console.log("no animate..."); 
    res( true )
});

cc.Class({
    extends: cc.Component,

    properties: {
        _hook_per : "__attr"
    },

    assignAnimate( CLASS ){
        this._Animate = new CLASS( this );
    },

    doAnimate(){
        if(!this._Animate) return emptyPromise;
        return this._Animate.do.apply(this._Animate , arguments );
    },

    childNode( namePath ){
        let node = $T.findChildNode( namePath , this.node );
        return node;
    },

    children( namePath ){
        if(namePath){
            let node = $T.findChildNode( namePath , this.node );
            if(node && node.parent){
                let tmp = node.parent.getChildren();
                let re = [];
                for(let i in tmp){
                    if(tmp[i].name == node.name){
                        re.push(tmp[i]);
                    }
                }
                return re;
            }else{
                return [];
            }
        }else{
            return this.node.getChildren();
        }
    },

    child( namePath , arr ){
        let node = $T.findChildNode( namePath , this.node );
        return node ? $T.getScr(node) : null;
    },

    //在子节点的脚本上执行指定方法
    doChild( childPath , meth ){
        let args = Array.prototype.slice.call( arguments );
        let target = this.child( childPath );
        target && $T.isType(target[meth] , "Function") && ( e =>{
            target[meth].apply( target , args.split(2) )
        })();
        return this;
    },

    //组件attr是自定义的一些属性 放在 this._data中集中管理
    getAttr( key , isAssign /*是否引用*/){
        isAssign = T.selectValue( isAssign , true );
        this._data = this._data || {};
        if( key ){
            return isAssign ? this._data[key] : T.clone(this._data[key]);
        }
        return isAssign ? this._data : T.clone( this._data )
    },

    clearAttr(){
        this._data = {};
        return this;
    },

    //setAttr 简写
    sa(){
        return this.setAttr.apply( this , arguments)
    },
    //getAttr 简写
    ga(){
        return this.setAttr.apply( this , arguments)
    },

    setAttr(){
        let attr="";
        let last="";
        this._data = this._data || {};
        let args = Array.prototype.slice.call(arguments);
        let wm = {
            add : (v , n)=>{
                n = T.selectValue(n , 1);
                return parseInt(v)+parseInt(n);
            },
            sub : (v , n)=>{
                n = T.selectValue(n , 1);
                return parseInt(v)-parseInt(n);
            },
            push : (o , v)=>{
                o = o || [];
                o.push(v);
                return o;
            }
        };

        let mkeya =null;

        if(args.length==2){
            let tmkeya = T.trimAll(args[0]).split("=>");
            if( tmkeya.length > 1){
                let t = {};
                t.key = tmkeya[0];
                t.meth = ()=>{
                    let tmp = tmkeya[1].split(":");
                    return wm[tmp[0]]( this._data[tmkeya[0]] , args[1] );
                }

                mkeya = t ;
            }else{
                mkeya = null;
            }
        }

        if(args.length == 1){
            let keya = T.trimAll(args[0]).split("=>");
            if(keya.length>1){
                attr = keya[0];
                last = this.getAttr(attr);
                this._data[keya[0]] = (()=>{
                    let tmp = keya[1].split(":");
                    return wm[tmp[0]]( parseInt(this._data[keya[0]]) , parseInt(tmp[1]?tmp[1]:1) );
                })()
            }else{
                this._data = T.clone( args[0] );
            }
        }else if( args.length == 2 ){
            if(mkeya){
                attr = mkeya['key'];
                last = this.getAttr(attr);
                this._data[mkeya['key']] = mkeya.meth();
            }else{
                attr = args[0];
                last = this.getAttr(attr);
                this._data[args[0]] = args[1];
            }
        }

        if(attr){
            let cur = this.getAttr( attr );
            this._runAttrHandlers( attr , last , cur );
        }
        return this;
    },

    isState( state ){
        return this.getAttr("__STATE") === state;
        //return this._state === state;
    },

    setState( state ){
        const last = this.getAttr("__last_STATE");
        this.setAttr("__last_STATE" , this.getAttr("__STATE") );
        //this._state = state;
        this.setAttr("__STATE" , state );
        if( $T.isType(this.onStateChanged , "Function")  && this.getAttr("__STATE")!=last  ){
            this.onStateChanged( this.getAttr("__last_STATE") , state );
        }

        // const last = this.getAttr("_last_state");
        // this.setAttr("_last_state" , this._state );
        // this._state = state;
        // if( $T.isType(this.onStateChanged , "Function")  && this._state!=last  ){
        //     this.onStateChanged( this.getAttr("_last_state") , state );
        // }
        return this;
    },

    resumeLastState(){        
        const last = this.getAttr("__last_STATE");
        if( !$T.isType(last , 'Undefined') ){
            let curState = this.getAttr("__STATE");
            this.setAttr("__last_STATE" , curState );
            this.setAttr("__STATE" , last );
            if( $T.isType(this.onStateChanged , "Function") && this.getAttr("__STATE")!=last ){
                this.onStateChanged(curState , last );
            } 
        }
        // const last = this.getAttr("_last_state");
        // if( !$T.isType(last , 'Undefined') ){
        //     let curState = this._state;
        //     this._state = last;
        //     if( $T.isType(this.onStateChanged , "Function") && this._state!=last ){
        //         this.onStateChanged(curState , last );
        //     } 
        // }
    },

    state(){
        return this.getAttr("__STATE");
    },

    lastState(){
        return this.getAttr("__last_STATE");
    },

    appendHookHandler( hookName , p ){
        this.__hook = this.__hook || new Hook();
        if( T.isType(p , "Function") ){
            p = {
                handler : p
            }
        }
        this.__hook.append( hookName , p );
    },

    runHook( hookName ){
        if(!this.__hook) return;
        let args = Array.prototype.slice.call( arguments , 1);
        this.__hook.run( hookName , ...args );
    },

    _runAttrHandlers( attr , last , cur ){
        if(!this.__hook) return;
        let hookStr = this._hook_per + attr;
        this.__hook.run( hookStr , last , cur );
    },

    //当运行条件还不成熟时，对一些逻辑处理做延迟执行
    pendding( handler , checkrun , params ){
        return new Promise(( res )=>{
            let p = {
                once : true,
                handler : handler , 
                destroy : ()=>{
                    res( p );
                }
            }
            checkrun && (p.checkrun = checkrun );
            params && (p.params = params);

            this.__hook.append( "peddings-handler" , p );
        })
    },

    //当某个状态变化为指定值时执行的逻辑钩子
    //value ：当变化为某个值时触发
    whenAttrRun( attr, handlerp , value){
        this.__hook = this.__hook || new Hook();
        let hookStr = this._hook_per + attr;
        let curV = this.getAttr( attr );
        if(!T.isType(value , "Undefined")){
            handlerp.checkrun = ()=>{ return this.getAttr(attr)===value };
        }

        this.__hook.append( hookStr , handlerp );
        if(curV===value){
            this.setAttr( attr , curV);
        }
    },

    whenAttrRunOnce( attr ,  handler , args  , value ){
        let params = {
            once : true , 
            handler : handler
        }
        args && (params.params = args);
        this.whenAttrRun( attr , params , value );
    },

    whenAttrChange( attr , handler , args ){
        this.__hook = this.__hook || new Hook();
        let hookStr = this._hook_per + attr;
        args = T.isType(args , "Array") ? args : (args || []);
        let handlerp = {
            handler : ( last , cur )=>{
                if( last !== cur){
                    let neargus = [last , cur];
                    neargus = Array.prototype.concat.call( [] , neargus, args );
                    handler( ...neargus );
                }
            }
        }
        args && ( handlerp.params = args )
        this.__hook.append( hookStr , handlerp );
    },

    update( dt ){
        // if(this.node.name == "gun"){
        //     console.log(dt);
        // }
        this.runHook( "update" , dt );
        this.runHook( "peddings-handler");
    }
});
